-- SteamMachineM
-- Created by panyl
-- 蒸汽机械

module("SteamMachineM", package.seeall);

-- 所有的规则处理子模块
local rules = {};

-- 石柱配置
local machines = {};

-- 内部函数声明
local whenPlayerMove;
local whenOpenGrid;
local whenSkyCombat;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    machines = {};

    -- 载入所有的规则处理子模块
    rules = LOAD_PATH("game/logic/module/steam_machine");

    -- 转换下machines信息表
    local steam_machine_CSV = get_steam_machine_CSV();
    for i = 1, #steam_machine_CSV do
        machines[steam_machine_CSV[i].class_id] = steam_machine_CSV[i];
    end

    steam_machine_CSV = {};
end

function init()
    loadCsv();

    -- 关注玩家离开地牢的事件
    EventMgr.removeAll("SteamMachineM");

    -- 每回合事件
    CombatM.registerEndRoundCB("steam_machine", whenPlayerMove);

    -- 每回合事件
    EventMgr.register("SteamMachineM", event.OPEN_GRID, whenOpenGrid);
    EventMgr.register("SteamMachineM", event.PURE_OPEN_GRID, whenOpenGrid);

    EventMgr.register("SteamMachineM", event.DUNGEON_SKY_COMBAT, whenSkyCombat);
end

-- 检索
function query(id, path)
    local m = machines[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 天空战斗
whenSkyCombat = function(para)
    local count = tonumber(para["win_times"]);
    local defenser_list = para["defenser_list"];

    count = math.min(count, sizeof(defenser_list));

    for i = 1, sizeof(defenser_list) do
        repeat
            local defenser_info = defenser_list[i];

            -- 如果不是蒸汽机械
            if not defenser_info["steam_machine"] then
                break;
            end

            local pos = defenser_info["grid_pos"];
            if not pos then
                break;
            end

            local grid = DungeonM.getGridByPos(pos + 1);
            if grid.type ~= GRID_TYPE_STEAM_MACHINE or not grid.steam_machine then
                break;
            end

            local tip = query(grid.steam_machine.classId, "intercept_tip");
            if sizeof(tip) > 0 then
                doAlert(tip);
            end

            -- 如果没有打赢。count之后的都是失败了
            if i > count then
                break;
            end

            -- 蒸汽机械变破碎了
            grid.broken = 1;

            EventMgr.fire(event.DEFEAT_AIRSHIP, {["class_id"] = defenser_info["steam_machine"], ["pos"] = pos, });
        until true;
    end
end

-- 每回合的回调
whenPlayerMove = function()
    for pos = 1, GRID_SIZE do
        repeat
            local grid = DungeonM.getGridByPos(pos);
            local machine = grid.steam_machine;

            if GRID_STATE_DISABLE == grid.state or 1 == grid.broken then
                break;
            end

            if not machine then
                break;
            end

            -- 尝试攻击
            machineAttack(machine);
        until true;
    end
end

whenOpenGrid = function(para)
    local pos = para["pos"];
    local grid = DungeonM.getGridByPos(pos);

    if not grid.steam_machine then
        return;
    end

    local list = { pos - 1, pos + 1, pos + 4, pos + 5, pos + 6, };
    for _, pos in ipairs(list) do
        grid = DungeonM.getGridByPos(pos);
        if not grid:isOpened() then
            grid:open();
        end
    end
end

-- 计算蒸汽机械cd
function calcMachineCd(machine)
    local attackRound = query(machine.classId, "attack_round");
    if type(attackRound) ~= "number" or attackRound <= 0 then
        return;
    end

    local grid = DungeonM.getGridByPos(machine:getPos());
    if grid.broken then
        return;
    end

    local lastAction = machine.dbase:query("action", 1);
    local nextRound = lastAction + attackRound;
    local curRound = CombatM.getRound();

    return nextRound - curRound;
end

-- 机械攻击
function machineAttack(machine)
    local cd = calcMachineCd(machine);
    if not cd or cd > 0 then
        return;
    end

    local mod = rules[query(machine.classId, "alias")];
    if not mod then
        return;
    end

    machine.dbase:set("action", CombatM.getRound());

    local damage = mod.calcDamage(machine);

    CombatM.receiveDamage(machine, ME.user, damage);

    EventMgr.fire(event.STEAM_ATTACK, {["pos"] = machine:getPos(), ["damage"] = damage});
end

-- 创建蒸汽机械
function createMachine(classId, para)
    trace("SteamMachineM", "生成蒸汽机械：%o", para);

    local dbase = table.add({
        ["class_id"] = classId,
        ["level"]    = 1,
        ["action"]   = 1,
    }, para);

    return SteamMachine.new(classId, dbase);
end

-- 进入机械内部
function enterMachine(pos)
    local grid = DungeonM.getGridByPos(pos);
    local machine = grid.steam_machine;

    -- 如果已经失效了
    if grid.state == GRID_STATE_DISABLE then
        return false;
    end

    if not machine then
        return false;
    end

    local instanceId = query(machine.classId, "instance_id");
    if type(instanceId) ~= "number" or instanceId <= 0 then
        return false;
    end

    return DungeonInstanceM.startInstance(pos, instanceId);
end

-- 获取所有存活的蒸汽机械
function getAliveMachines()
    local ret = {};
    for pos = 1, GRID_SIZE do
        local grid = DungeonM.getGridByPos(pos);
        if grid.steam_machine and grid.state ~= GRID_STATE_DISABLE and grid.broken ~= 1 then
            table.insert(ret, grid);
        end
    end

    return ret;
end

-- 格子是否可以点击
function canHit(pos)
    local indexs = {pos, pos-1, pos+1, pos+4, pos+5, pos+6};
    for _, index in pairs(indexs) do
        local grid = DungeonM.getGridByPos(index);
        if grid:canHit() then
            -- 有一个是联通的就可以点击了
            return true;
        end
    end

    return false;
end

function canRepairRobot(grid)
    local element = grid.element;
    local dbase = DungeonM.queryElement(element, "dbase") or {};

    local manual = dbase["engineering_manual"] or 0;
    local pets = dbase["combat_pets"] or {};
    local active_pet = ME.user.dbase:query("active_pet");

    -- 没满足条件
    if not EngineeringManualM.subjectOver(manual) and table.indexOf(pets, active_pet) <= 0 then
        return false;
    end

    return true;
end

-- 机器人残骸
function takeRobot(pos, data)
    local grid = DungeonM.getGridByPos(pos);
    if grid.type ~= GRID_TYPE_BROKEN_ROBOT or grid.state == GRID_STATE_DISABLE then
        return false;
    end

    local bonus = {};
    local tips;
    local element = grid.element;

    grid:changeState(GRID_STATE_DISABLE);

    -- 如果是修复
    if 1 == data then
        local dbase = DungeonM.queryElement(element, "dbase") or {};

        -- 没满足条件
        if not canRepairRobot(grid) then
            bonus = {};

            tips = BuildingBonusM.queryBuildingView(grid.class, "fail_tip");
        else
            -- 机器人
            bonus = { 8, dbase["robot_id"], 1, };

            tips = BuildingBonusM.queryBuildingView(grid.class, "bonus_tip");
        end
    else
        local args = DungeonM.queryElement(element, "args") or {};

        bonus = args["bonus"];
        if sizeof(bonus) <= 0 then
            return false;
        end
    end

    if sizeof(bonus) > 0 then
        BonusM.doBonus(bonus);
    end

    -- 抛出通用建筑奖励事件
    EventMgr.fire(event.COMM_BUILDING_BONUS, {
        ["pos"]   = pos,
        ["type"]  = grid.type,
        ["bonus"] = {["bonus"] = bonus,},
        ["remainGrid"] = false,
        ["tips"] = tips,
        -- ["desc"] = desc,
    });

    return true;
end
